package de.mrapp.ohos_util.logging;

import de.mrapp.util.ClassUtil;
import de.mrapp.util.Condition;

import java.util.logging.Level;

public class Logger {

    /**
     * The current log level.
     */
    private LogLevel logLevel;

    /**
     * Creates a new logger, which uses a specific log level.
     *
     * @param logLevel
     *         The log level, which should be used by the logger, as a value of the enum {@link
     *         LogLevel}. The log level may not be null
     */
    public Logger(final LogLevel logLevel) {
        setLogLevel(logLevel);
    }

    /**
     * Returns the current log level. Only log messages with a rank greater or equal than the rank
     * of the currently applied log level, are written to the output.
     *
     * @return The current log level as a value of the enum {@link LogLevel}. The log level may
     * either be <code>ALL</code>, <code>DEBUG</code>, <code>INFO</code>, <code>WARN</code>,
     * <code>ERROR</code> or <code>OFF</code>
     */
    public final LogLevel getLogLevel() {
        return logLevel;
    }

    /**
     * Sets the log level. Only log messages with a rank greater or equal than the rank of the
     * currently applied log level, are written to the output.
     *
     * @param logLevel
     *         The log level, which should be set, as a value of the enum {@link LogLevel}. The log
     *         level may not be null
     */
    public final void setLogLevel(final LogLevel logLevel) {
        Condition.INSTANCE.ensureNotNull(logLevel, "The log level may not be null");
        this.logLevel = logLevel;
    }

    /**
     * Logs a specific message on the log level VERBOSE.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     */
    public final void logVerbose(final Class<?> tag, final String message) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");

        if (LogLevel.VERBOSE.getRank() >= getLogLevel().getRank()) {

            java.util.logging.Logger.getGlobal().log(Level.CONFIG, message , ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message and exception on the log level VERBOSE.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     * @param cause
     *         The exception, which caused the log message, as an instance of the class {@link
     *         Throwable}. The cause may not be null
     */
    public final void logVerbose(final Class<?> tag, final String message,
                                 final Throwable cause) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");
        Condition.INSTANCE.ensureNotNull(cause, "The cause may not be null");

        if (LogLevel.VERBOSE.getRank() >= getLogLevel().getRank()) {
//            Log.v(ClassUtil.getTruncatedName(tag), message, cause);
            java.util.logging.Logger.getGlobal().log(Level.CONFIG, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message on the log level DEBUG.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     */
    public final void logDebug(final Class<?> tag, final String message) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");

        if (LogLevel.DEBUG.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.FINE, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message and exception on the log level DEBUG.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     * @param cause
     *         The exception, which caused the log message, as an instance of the class {@link
     *         Throwable}. The cause may not be null
     */
    public final void logDebug(final Class<?> tag, final String message,
                               final Throwable cause) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");
        Condition.INSTANCE.ensureNotNull(cause, "The cause may not be null");

        if (LogLevel.DEBUG.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.FINE, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message on the log level INFO.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     */
    public final void logInfo(final Class<?> tag, final String message) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");

        if (LogLevel.INFO.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.INFO, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message and exception on the log level INFO.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     * @param cause
     *         The exception, which caused the log message, as an instance of the class {@link
     *         Throwable}. The cause may not be null
     */
    public final void logInfo(final Class<?> tag, final String message,
                              final Throwable cause) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");
        Condition.INSTANCE.ensureNotNull(cause, "The cause may not be null");

        if (LogLevel.INFO.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.INFO, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message on the log level WARN.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     */
    public final void logWarn(final Class<?> tag, final String message) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");

        if (LogLevel.WARN.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.WARNING, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message and exception on the log level WARN.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     * @param cause
     *         The exception, which caused the log message, as an instance of the class {@link
     *         Throwable}. The cause may not be null
     */
    public final void logWarn(final Class<?> tag, final String message,
                              final Throwable cause) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");
        Condition.INSTANCE.ensureNotNull(cause, "The cause may not be null");

        if (LogLevel.WARN.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.WARNING, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message on the log level ERROR.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     */
    public final void logError(final Class<?> tag, final String message) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");

        if (LogLevel.ERROR.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.SEVERE, message, ClassUtil.getTruncatedName(tag));
        }
    }

    /**
     * Logs a specific message and exception on the log level ERROR.
     *
     * @param tag
     *         The tag, which identifies the source of the log message, as an instance of the class
     *         {@link Class}. The tag may not be null
     * @param message
     *         The message, which should be logged, as a {@link String}. The message may neither be
     *         null, nor empty
     * @param cause
     *         The exception, which caused the log message, as an instance of the class {@link
     *         Throwable}. The cause may not be null
     */
    public final void logError(final Class<?> tag, final String message,
                               final Throwable cause) {
        Condition.INSTANCE.ensureNotNull(tag, "The tag may not be null");
        Condition.INSTANCE.ensureNotNull(message, "The message may not be null");
        Condition.INSTANCE.ensureNotEmpty(message, "The message may not be empty");
        Condition.INSTANCE.ensureNotNull(cause, "The cause may not be null");

        if (LogLevel.ERROR.getRank() >= getLogLevel().getRank()) {
            java.util.logging.Logger.getGlobal().log(Level.SEVERE, message, ClassUtil.getTruncatedName(tag));
        }
    }
}
